#include <stdio.h>
#include <stdlib.h>
#include "Common/Debug.h"
#include "Thread.h"

void os_ThreadCreate(int priority, TThread *thread, TThreadFuncPtr func, TThreadFuncArg func_arg, int stack_size, void *stack_addr)
{
	struct sched_param param;
	pthread_attr_t	attr;

//	ASSERT_DEBUG(stack_size >= PTHREAD_STACK_MIN);

	if (pthread_attr_init(&attr) != 0)
	{
		LOG("os_ThreadCreate: init attributes object error!\n");
		return;
	}

#ifdef SUPPORT_PTHREAD_ATTR_SETSTACK	
	if (pthread_attr_setstack(&attr, stack_addr, stack_size) != 0)
	{
		LOG("os_ThreadCreate: set stack error! (%d bytes)\n", stack_size);
	}	
#else
	if (pthread_attr_setstacksize(&attr, stack_size) != 0)
	{
		LOG("os_ThreadCreate: set stack size error! (%d bytes)\n", stack_size);
	}
	
	if (stack_addr)
	{
		if (pthread_attr_setstackaddr(&attr, stack_addr) != 0)
		{
			LOG("os_ThreadCreate: set stack addr error!\n");
		}
	}
#endif

	if (pthread_create(thread, &attr, func, func_arg) != 0)
	{
		LOG("os_ThreadCreate: create thread error!\n");
	}
	else
	{
		os_ThreadSuspend(*thread);

		param.sched_priority = priority;
		pthread_attr_setschedparam( &attr, &param );
	}
}

void os_SetThreadPriority(TThread thread, int priority)
{
//	pthread_setschedprio(thread, priority); ??
//	pthread_getschedparam
//	pthread_attr_setschedparam
//	ASSERT_DEBUG(rval == 0);
}

int os_GetThreadPriority(TThread thread)
{
//	pthread_getschedparam ??
//	pthread_attr_getschedparam
//	ASSERT_DEBUG(0);	
	return 0;	
}

// Allow a thread to terminate itself
void os_ThreadExit()
{
	pthread_exit(NULL);
}

// Suspends the specified thread and the thread's suspend count is incremented
// NOTE: scheduler will never run a thread with a non-zero suspend counter. 
void os_ThreadSuspend(TThread thread)
{
//	don't supported directly
//	ASSERT_DEBUG(0);
}

// Decrement the suspend counter
// NOTE: when the suspend count is decremented to zero, the execution of the
//		 thread is resumed.
void os_ThreadResume(TThread thread)
{
//	don't supported directly
//	ASSERT_DEBUG(0);
}

// Force the calling thread to relinquish use of its processor, and to wait
// in the run queue before it is scheduled again
void os_ThreadYield()
{
//	pthread_yield();
//	pl1061 not supported!
//	ASSERT_DEBUG(0);
}

// Wait for thread termination 
void os_ThreadJoin(TThread thread)
{
	pthread_join(thread, NULL);
}


// Initialize a mutex
// NOTE: if a mutex is no longer required and there are no threads waiting
//       on it then call os_MutexDestroy.
void os_MutexInit(TMutex *mutex)
{
	pthread_mutex_init(mutex, NULL);
}

// Destroy a mutex
// NOTE: attempting to destroy a locked mutex results in undefined behavior.
void os_MutexDestroy(TMutex *mutex)
{
	pthread_mutex_destroy(mutex);
}

// Lock a mutex
// NOTE: return after claiming the mutex lock, blocking if another thread
//		 currently owns the mutex.
void os_MutexLock(TMutex *mutex)
{
	pthread_mutex_lock(mutex);

//	LOG("%x locked\n", mutex);
}

// Unlock a mutex
// NOTE: the current owner of a mutex should call os_MutexUnlock when a lock
//		 is no longer required. This operation must be performed by the owner,
//		 not by another thread.
void os_MutexUnlock(TMutex *mutex)
{
	pthread_mutex_unlock(mutex);

//	LOG("%x unlocked\n", mutex);
}

